package com.zhihuishu.micro.course.service.impl;

import com.zhihuishu.micro.course.dto.LessonDto;
import com.zhihuishu.micro.course.dto.LessonVideoDto;
import com.zhihuishu.micro.course.helper.LogModule;
import com.zhihuishu.micro.course.helper.RemoteLogHelper;
import com.zhihuishu.micro.course.model.LessonVideo;
import com.zhihuishu.micro.course.model.LessonVideoCount;
import com.zhihuishu.micro.course.service.*;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;

@Service("lessonVideoAllService")
public class LessonVideoAllServiceImpl extends BaseTreenityBatchServiceImpl<LessonVideoDto> implements LessonVideoTreenityService {
    private final static String moduleCN = "小节";
    @Resource
    private LessonVideoTreenityDBService lessonVideoAllServiceDB;

    @Resource
    private LessonVideoTreenityRedisService lessonVideoAllServiceRedis;

    /* 用来更新节信息——小节数目*/
    @Resource
    private LessonTreenityService lessonAllService;

    
    @Resource
    private LessonTestQuestionService lessonTestQuestionService;
    
    
    @Override
    protected TreenityBatchDBService<LessonVideoDto, ?> getDBService() {
        return lessonVideoAllServiceDB;
    }

    @Override
    protected Class<LessonVideoDto> getDTOClass() {
        return LessonVideoDto.class;
    }

    @Override
    protected TreenityBatchRedisService<LessonVideoDto> getRedisService() {
        return lessonVideoAllServiceRedis;
    }


    @Override
    public Integer create(LessonVideoDto lessonVideo, long creator) {
        Assert.notNull(lessonVideo, moduleCN + "对象为空!");
        Assert.notNull(lessonVideo.getCourseId(), moduleCN + "所属课程ID为空!");
        Assert.notNull(lessonVideo.getChapterId(), moduleCN + "所属章ID为空!");
        Assert.notNull(lessonVideo.getLessonId(), moduleCN + "所属小节ID为空!");
        Assert.notNull(lessonVideo.getRank(), moduleCN + "序号为空!");
        Assert.notNull(lessonVideo.getVideoId(), moduleCN + "视频id为空!");
        RemoteLogHelper.log(LogModule.CHAPTER_LESSON_VIDEO.getCode(), creator, "[开始]创建" + moduleCN + "[节ID：{}/序号：{}]", lessonVideo.getChapterId(), lessonVideo.getRank());

        Integer createdLvsId = super.create(lessonVideo, creator);

        RemoteLogHelper.log(LogModule.CHAPTER_LESSON_VIDEO.getCode(), creator
                , "[完成]创建" + moduleCN + "[节ID：{}/序号：{}]({})"
                , lessonVideo.getChapterId(), lessonVideo.getRank(), createdLvsId);

        //更新节下字段-小节数
        UpdateLessonChildrenCountResult upRs = updateLessonChildrenCount(createdLvsId, creator);

        //添加该小节的视频缓存
        updateVideoCacheWhenAdd(lessonVideo, createdLvsId, upRs);
        
        //弹题缓存（添加一个小节）
        if (upRs.current == 2) {
        	lessonTestQuestionService.updateLessonTestByAddLesson(upRs.lessonId.intValue(), upRs.getFirstVideoInfo().getId());
        }
        
        return createdLvsId;
    }


    private Integer convertToInt(Long l) {
        if (l != null) {
            return l.intValue();
        }
        return null;
    }

    @Override
    public void delete(Integer lessonVideoId, long deleteUserId) {
        //overwrite
        Assert.notNull(lessonVideoId, "dtoId不能为空");

        getDBService().delete(lessonVideoId, deleteUserId);

        LessonVideoDto detail = detail(lessonVideoId);

        //remove relationship
        if (detail != null && !StringUtils.isEmpty(detail.getCourseId())) {
            getRedisService().deleteRelationShip(detail.getCourseId(), lessonVideoId);
        }

        getRedisService().delete(lessonVideoId, deleteUserId);
        //overwrite end

        //更新节下字段-小节数
        UpdateLessonChildrenCountResult upRs = updateLessonChildrenCount(lessonVideoId, deleteUserId);

        //删除该小节的视频缓存(若没转码，则存在)
        updateVideoCacheWhenRemove(detail, upRs);
        
        //弹题缓存（删除一个小节）
       
        lessonTestQuestionService.updateLessonTestByDelLesson(upRs.lessonId.intValue(), lessonVideoId);
        
    }

    @Override
    public void update(LessonVideoDto chapterDto, long updateUserId) {
        //overwrite start
        Assert.notNull(chapterDto);
        Integer dtoId = chapterDto.getId();
        Assert.notNull(dtoId);

        // 更新数据库中的章
        getDBService().update(chapterDto, updateUserId);

        //直接查库，然后更新缓存
        LessonVideoDto detailInDB = getDBService().detail(dtoId);
        log.debug("update {} from params:[{}]!", getDTOName(), String.valueOf(chapterDto));
        log.debug("update {} from db:[{}]!", getDTOName(), String.valueOf(detailInDB));

        getRedisService().update(detailInDB, updateUserId);

        log.warn("执行更新dto:[{}]，更新人[{}]!", dtoId, updateUserId);
        //overwrite end

        Long videoId = chapterDto.getVideoId();
        if (videoId != null) {
            //更新该小节的视频缓存(若没转码，则存在)
            updateVideoCacheWhenUpdate(dtoId, detailInDB, videoId);
        }

    }

    private void updateVideoCacheWhenAdd(LessonVideoDto lessonVideo, Integer createdLvsId, UpdateLessonChildrenCountResult upRs) {
        Long videoId = lessonVideo.getVideoId();

        // 将其加入"cc:video:" + videoId + ":lvs;
        lessonVideoAllServiceRedis.updateVideoIdRedis(convertToInt(videoId), null, createdLvsId);

        //若此时节下只有1个视频，
        //加入 "cc:video:" + videoId + ":lessons ;
        if (upRs.current == 1) {
            lessonVideoAllServiceRedis.updateVideoIdRedis(convertToInt(videoId), convertToInt(lessonVideo.getLessonId()), null);
        }

        if (upRs.current == 2) {
            // 若节下有2个视频，
            // 将第一个从 "cc:video:" + videoId + ":lessons" 移除
            LessonVideo videoInfo = upRs.getFirstVideoInfo();
            Integer firstVideoId = convertToInt(videoInfo.getVideoId());
            Integer firstLessonId = convertToInt(videoInfo.getLessonId());
            Long deleted = lessonVideoAllServiceRedis.deleteVideoIdRedis(firstVideoId, firstLessonId, null);
        }
    }

    private void updateVideoCacheWhenUpdate(Integer dtoId, LessonVideoDto detailInDB, Long videoId) {
        UpdateLessonChildrenCountResult upRs = queryLessonChildrenInfo(dtoId);

        // 将其 加入"cc:video:" + videoId + ":lvs;
        lessonVideoAllServiceRedis.updateVideoIdRedis(convertToInt(videoId), null, dtoId);

        //若此时节下只有1个视频，
        //加入 "cc:video:" + videoId + ":lessons ;
        if (upRs.current == 1) {
            lessonVideoAllServiceRedis.updateVideoIdRedis(convertToInt(videoId), convertToInt(detailInDB.getLessonId()), null);
        }
    }

    private void updateVideoCacheWhenRemove(LessonVideoDto detail, UpdateLessonChildrenCountResult upRs) {
        lessonVideoAllServiceRedis.deleteVideoIdRedis(convertToInt(detail.getVideoId()), null, detail.getId());

        //若此时节下只剩1个视频，
        //  加入"cc:video:" + videoId + ":lessons
        if (upRs.current == 1) {
            LessonVideo videoInfo = upRs.getFirstVideoInfo();
            Integer firstVideoId = convertToInt(videoInfo.getVideoId());
            Integer firstLessonId = convertToInt(videoInfo.getLessonId());
            lessonVideoAllServiceRedis.updateVideoIdRedis(firstVideoId, firstLessonId, null);
        }

        //若此时节下只剩0个视频，
        //  说明删除的是最后一个 删除其"cc:video:" + videoId + ":lessons
        if (upRs.current == 0) {
            Long lastLessonId = upRs.lessonId;
            Integer lastVideoId = convertToInt(detail.getVideoId());
            Long deleted = lessonVideoAllServiceRedis.deleteVideoIdRedis(lastVideoId, convertToInt(lastLessonId), null);
        }
    }

    private UpdateLessonChildrenCountResult queryLessonChildrenInfo(Integer lessonVideoId) {
        UpdateLessonChildrenCountResult rs = new UpdateLessonChildrenCountResult();
        LessonVideoCount lessonVideoCount = lessonVideoAllServiceDB.countLvsAndGetLessonId(lessonVideoId);
        Integer current = lessonVideoCount.getCount();
        Long lessonId = lessonVideoCount.getLessonId();
        rs.current = current;
        rs.lessonId = lessonId;
        return rs;
    }

    /**
     * 当节下视频数=1时，这时认为视频挂在节下面，所以需要更新节的视频信息
     * 其它情况都视作节没有视频信息，视频信息存在于其下小节之中。
     *
     * @param lessonVideoId
     * @param userId
     */
    private UpdateLessonChildrenCountResult updateLessonChildrenCount(Integer lessonVideoId, long userId) {
        UpdateLessonChildrenCountResult rs = queryLessonChildrenInfo(lessonVideoId);

        LessonDto update = new LessonDto();

        update.setId(convertToInt(rs.lessonId));
        if (rs.current == 1) {
            //children to 0
            update.setHaveChildren(0);

            LessonVideo videoInfo = rs.getFirstVideoInfo();

            update.setVideoId(videoInfo.getVideoId());
            update.setVideoImg(videoInfo.getVideoImg());
            update.setVideoSec(videoInfo.getVideoSec());

            lessonAllService.update(update, userId);
        } else {
            //children to current count
            update.setHaveChildren(rs.current);

            update.setVideoId(null);
            update.setVideoImg(null);
            update.setVideoSec(null);

            lessonAllService.clearVideoInfo(update, userId);
        }


       
        
        
        return rs;

    }

    @Override
    public void updateVideoIdRedis(Integer videoId, Integer lessonId, Integer lesssonVideoId) {
        lessonVideoAllServiceRedis.updateVideoIdRedis(videoId, lessonId, lesssonVideoId);

    }

    class UpdateLessonChildrenCountResult {
        Integer current;
        Long lessonId;
        LessonVideo firstVideoInfo;

        public LessonVideo getFirstVideoInfo() {
            if (this.firstVideoInfo == null) {
                this.firstVideoInfo = lessonVideoAllServiceDB.selectFirstVideoInfo(this.lessonId);
            }
            return firstVideoInfo;
        }
    }
}
